﻿#include "VulkanCircleWidget.h"
#include "Render/VulkanContext.h"
#include "Render/Widget/VulkanWindow.h"

CVulkanCircleWidgets::~CVulkanCircleWidgets()
{
    //销毁command buffer
    CVulkanContext::Get()->GetRecycleObjects()->CommandBuffers.Add(CommandBuffer);

}

void CVulkanCircleWidgets::PreProcess(const TVector<SPreRenderCircleWidget> &AllCircleData)
{
    TVector<SPreRenderCircleWidget> ValidData;
    ValidData.Reserve(AllCircleData.Num());

    for (const auto& CircleData : AllCircleData)
    {
        //检查数据是否合法
        if(CircleData.Color.A==0)
        {
            continue;
        }

        if(CircleData.Radius<=0)
        {
            continue;
        }

        if(CircleData.Viewport.width<=0 || CircleData.Viewport.height<=0)
        {
            continue;
        }

        //检查裁剪是否合法
        if(CircleData.Scissor.extent.width<=0 || CircleData.Scissor.extent.height<=0)
        {
            continue;
        }

        //如果裁剪矩形完全在视口外面，则不需要绘制
        if(CircleData.Scissor.offset.x+CircleData.Scissor.extent.width<=CircleData.Viewport.x ||
            CircleData.Scissor.offset.x>=CircleData.Viewport.x+CircleData.Viewport.width ||
            CircleData.Scissor.offset.y+CircleData.Scissor.extent.height<=CircleData.Viewport.y ||
            CircleData.Scissor.offset.y>=CircleData.Viewport.y+CircleData.Viewport.height)
        {
            continue;
        }

        ValidData.Add(CircleData);

    };

    //创建渲染对象
    CircleWidgets.Resize(ValidData.Num());
    for (int i = 0; i < ValidData.Num(); ++i)
    {
        CircleWidgets[i].BindData(ValidData[i]);
    }

}

void CVulkanCircleWidgets::CreateSelfRecordTasks(CVulkanWindow *InRenderSurface, SRenderCommandBuffers &OutCmdBuffersToExecute)
{
    if(CircleWidgets.Num()==0)
    {
        return;
    }

    //创建command buffer
    if(!CommandBuffer)
    {
        //allocate a command buffer for this widget
        vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::eSecondary)
            .setCommandBufferCount(1);

        CommandBuffer = CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
    }


    OutCmdBuffersToExecute.RectWidgetRenderPassCommandBuffers.Add(CommandBuffer);

    vk::CommandBufferInheritanceInfo CommandBufferInheritanceInfo=vk::CommandBufferInheritanceInfo()
        .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
        .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
        .setSubpass(0)
    ;

    vk::CommandBufferBeginInfo CommandBufferBeginInfo=vk::CommandBufferBeginInfo()
        .setFlags(vk::CommandBufferUsageFlagBits::eRenderPassContinue)
        .setPInheritanceInfo(&CommandBufferInheritanceInfo);

    CommandBuffer.begin(CommandBufferBeginInfo);
    //绑定pipeline
    CommandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics
        ,CVulkanContext::Get()->GetWidgetPipelines()->CircleWidgetPipeline);

    for (auto& CircleWidget : CircleWidgets)
    {
        CircleWidget.Draw(CommandBuffer);
    }

    CommandBuffer.end();

}

void CVulkanCircleWidget::BindData(const SPreRenderCircleWidget& InData)
{
    Data = InData;
}

void CVulkanCircleWidget::Draw(vk::CommandBuffer CommandBuffer)
{
    //推送常量
    SWidgetPipelines::SCircleWidgetVertexPushConstant PushConstantValue;
    PushConstantValue.Color[0]=Data.Color.R;
    PushConstantValue.Color[1]=Data.Color.G;
    PushConstantValue.Color[2]=Data.Color.B;
    PushConstantValue.Color[3]=Data.Color.A;
    PushConstantValue.ZOrder=Data.Depth;
    PushConstantValue.Center[0]=Data.Center.X;
    PushConstantValue.Center[1]=Data.Center.Y;
    PushConstantValue.Radius=Data.Radius;

                    
    CommandBuffer.pushConstants(
        CVulkanContext::Get()->GetWidgetPipelines()->CircleWidgetPipelineLayout
        ,vk::ShaderStageFlagBits::eVertex
        ,0
        ,sizeof(SWidgetPipelines::SCircleWidgetVertexPushConstant)
        ,&PushConstantValue);


    CommandBuffer.setViewport(0,1,&Data.Viewport);
    CommandBuffer.setScissor(0,1,&Data.Scissor);
                       

    CommandBuffer.draw(4,1,0,0);    
}
